/*
 * File:   DataBase.cpp
 * Author: wilq
 *
 * Created on June 6, 2012, 4:06 PM
 */

#include "DataBase.h"
#include "Group.h"
#include <memory>
#include <algorithm>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/lexical_cast.hpp>

using namespace std;
using namespace CSDatabaseLib;
#define SYNC_TIME 60 /*60 seconds*/
#define LOCK_GUARD_WRITE DBTransaction lock(this, false);
#define LOCK_GUARD_READ DBTransaction lock(this, true);



inline std::string  TrimString(const std::string &str)
{
	std::string tmp(str);
	while((!tmp.empty()) && ((char)(' ')==tmp[0])) {tmp.erase(tmp.begin());}
	while((!tmp.empty()) && ((char)(' ')==tmp[tmp.size()-1])) {	tmp.erase(tmp.end()-1); }
	return tmp;
}

//###########################################################################################################################

DataBase::DataBase(const std::string &ip,const std::string &userName,const std::string &password,const std::string &schema) {
    FUNCTION_TRACK
    interface = NULL;
    try {
        driver = get_driver_instance();
        con = driver->connect(ip, userName, password);
        con->setSchema(schema);
		con->setAutoCommit(false);
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }
}

bool DataBase::isConnected() {
    FUNCTION_TRACK
    return con != NULL && driver != NULL && !con->isClosed();
}

DataBase::DataBase(const DataBase& orig) {
    FUNCTION_TRACK
}

DataBase::~DataBase() {
    FUNCTION_TRACK
    delete con;
    con = NULL;
}

std::string DataBase::crypt(const std::string &str) {
    FUNCTION_TRACK
    return std::string(str); //TODO
}

/************************************************************ Used by storage ***************************************************************/

uint64_t DataBase::LastInsertId()
{
    std::auto_ptr<sql::Statement> stmt(con->createStatement());
    std::auto_ptr<sql::ResultSet> res(stmt->executeQuery("SELECT LAST_INSERT_ID();"));
    if (res->next()) {
        return res->getUInt64(1);
    }
	else
	{
		throw sql::SQLException("LAST_INSERT_ID() return no rows");
	}
}

/* Storage auth method, return 0 or storage id */
int32_t DataBase::StorageAuth(const std::string &name, const std::string &key) {
    FUNCTION_TRACK
	LOCK_GUARD_READ

    try {
        std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("SELECT id FROM Storages WHERE name = ? AND password = ? LIMIT 1"));
        pstmt->setString(1, name);
        pstmt->setString(2, crypt(key));

        std::auto_ptr<sql::ResultSet> res(pstmt->executeQuery());
        if (res->next()) {
            return res->getInt(1);
        }
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return 0;
}

/* Update folder data if exists, creating one with rights and owner ship copied from parent if no exists*/
void DataBase::StorageFolderUpdate(const std::string &link, const std::string &parentLink, const std::string& name, bool sync, uint32_t storageId)
{
	FUNCTION_TRACK
	LOCK_GUARD_WRITE
    try {
			std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("UPDATE `Folders` SET `last_sync_date` = CURRENT_TIMESTAMP"+std::string(sync?", `last_modification_date` = CURRENT_TIMESTAMP":"")+" WHERE link = ? AND id_storage = ?"));
			pstmt->setString(1, link);
			pstmt->setUInt(2, storageId);
			pstmt->executeUpdate();

			pstmt.reset(con->prepareStatement("SELECT a.id, a.rights, a.owner_user, a.owner_group, b.id as bid  FROM `Folders` as a LEFT JOIN `Folders` as b ON (a.id = b.parent_id AND b.name = ? AND b.id_storage <> ? AND b.link <> ?) WHERE a.link = ? AND a.id_storage = ?"));
			pstmt->setString(1, name);
			pstmt->setUInt(2, storageId);
			pstmt->setString(3, link);
			pstmt->setString(4, parentLink);
			pstmt->setUInt(5, storageId);
			std::auto_ptr<sql::ResultSet> res(pstmt->executeQuery());

			std::auto_ptr<sql::PreparedStatement> ustmt(con->prepareStatement("UPDATE `Folders` SET rights = ?, create_date = CURRENT_TIMESTAMP"+std::string(sync?", `last_modification_date` = CURRENT_TIMESTAMP":"")+", last_sync_date = CURRENT_TIMESTAMP, owner_user = ?, owner_group = ?, link = ?, id_storage = ? WHERE id = ?"));
			ustmt->setString(4, link);
			ustmt->setUInt(5, storageId);

			std::auto_ptr<sql::PreparedStatement> ustmt2(con->prepareStatement("UPDATE `Folders` SET last_sync_date = CURRENT_TIMESTAMP"+std::string(sync?", `last_modification_date` = CURRENT_TIMESTAMP":"")+" WHERE id = ?"));

			while(res->next())
			{
				if (res->isNull(5))
				{
					int32_t folder = FolderCreate(name, res->getUInt(1), res->getUInt(2), res->getUInt(3), res->getUInt(4), storageId, link, sync);
					if (folder>0)
					{
						ustmt2->setUInt(1, folder);
						ustmt2->executeUpdate();
					}
				}
				else
				{
					ustmt->setUInt(1, res->getUInt(2));
					ustmt->setUInt(2, res->getUInt(3));
					ustmt->setUInt(3, res->getUInt(4));
					ustmt->setUInt(6, res->getUInt(5));
					ustmt->executeUpdate();
				}
			}
			lock.Commit();
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }
}

/* Remove folder and subfolders and files from same storage, if folder got files/folders from other storages, leave folder as pure virtual */
void DataBase::StorageFolderRemove(const std::string &link, uint32_t storageId)
{
	FUNCTION_TRACK
	LOCK_GUARD_WRITE

     try {
         std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("SELECT a.id FROM Folders as a WHERE a.link = ? AND a.id_storage = ? ORDER BY a.left_id ASC"));
         pstmt->setString(1, link);
         pstmt->setUInt(2, storageId);
         std::auto_ptr<sql::ResultSet> res(pstmt->executeQuery());
         while (res->next())
         {
               this->FolderRemove(res->getUInt(1), storageId, 0);
         }
     } catch (sql::SQLException &e) {
         LOG_EXCEPTION
     }
}

/* Update file data if exists, creating one with rights and owner ship copied from parent */
void DataBase::StorageFileUpdate(const std::string &link, const std::string &parentLink, const std::string& name, int64_t size, uint64_t lastWriteTime, uint32_t storageId)
{
	FUNCTION_TRACK
	LOCK_GUARD_WRITE
    try {
			std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("UPDATE `File` SET last_modification_date = FROM_UNIXTIME(?), last_sync_date = CURRENT_TIMESTAMP, `size` = ? WHERE id_storage = ? AND link = ?"));
			pstmt->setUInt64(1, lastWriteTime);
			pstmt->setUInt64(2, size);
			pstmt->setString(4, link);
			pstmt->setUInt(3, storageId);
			INFO("StorageFileUpdate: Updated files - %d - %d - %s", pstmt->executeUpdate(), storageId, link.c_str());

			pstmt.reset(con->prepareStatement("SELECT b.id, b.rights, b.owner_user, b.owner_group, a.id as id2 FROM `Folders` as b  LEFT JOIN `File` as a  ON (a.folder_id = b.id AND a.name = ?) WHERE b.link = ? AND b.id_storage = ? AND ((a.id is null) OR (a.link <> ?))"));
			pstmt->setString(1, name);
			pstmt->setString(2, parentLink);
			pstmt->setUInt(3, storageId);
			pstmt->setString(4, link);

			std::auto_ptr<sql::PreparedStatement> ustmt(con->prepareStatement("UPDATE `File` SET last_modification_date = FROM_UNIXTIME(?), last_sync_date = CURRENT_TIMESTAMP, `size` = ?, rights = ?, create_date = CURRENT_TIMESTAMP, owner_user = ?, owner_group = ?, id_storage = ?, link = ? WHERE id = ?"));
			ustmt->setUInt64(1, lastWriteTime);
			ustmt->setUInt64(2, size);
			ustmt->setUInt(6, storageId);
			ustmt->setString(7, link);

			std::auto_ptr<sql::PreparedStatement> istmt(con->prepareStatement("INSERT INTO `File` (`folder_id`, `name`, `rights`, `last_modification_date`, `last_sync_date`, `owner_user`, `owner_group`, `size`, `link`, `id_storage`) VALUES(?, ?, ?, FROM_UNIXTIME(?), CURRENT_TIMESTAMP, ?, ?, ?, ?, ?);"));
			istmt->setString(2, name);
			istmt->setUInt64(4, lastWriteTime);
			istmt->setUInt64(7, size);
			istmt->setString(8, link);
			istmt->setUInt(9, storageId);

			std::auto_ptr<sql::ResultSet> res(pstmt->executeQuery());
			while (res->next())
			{
				if (res->isNull(5))
				{
					istmt->setUInt(1, res->getUInt(1));
					istmt->setUInt(3, res->getUInt(2));
                    istmt->setUInt(5, res->getUInt(3));
					if (!res->isNull(4))
						istmt->setUInt(6, res->getUInt(4));
					else
						istmt->setNull(6, sql::DataType::INTEGER);
					istmt->executeUpdate();
				}
				else
				{
					ustmt->setUInt(3, res->getUInt(2));
					ustmt->setUInt(4, res->getUInt(3));
					if (!res->isNull(4))
						istmt->setUInt(5, res->getUInt(4));
					else
						istmt->setNull(5, sql::DataType::INTEGER);
					ustmt->setUInt(8, res->getUInt(5));
					ustmt->executeUpdate();
				}
			}

			lock.Commit();
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }
}

/* Remove file if exists */
void DataBase::StorageFileRemove(const std::string &link, uint32_t storageId)
{
	FUNCTION_TRACK
	LOCK_GUARD_WRITE
    try {
			std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("DELETE FROM `File` WHERE `link` = ? AND `id_storage` = ?"));
			pstmt->setString(1, link);
			pstmt->setUInt(2, storageId);
			pstmt->executeUpdate();

			lock.Commit();
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }
}

int32_t DataBase::UserAdd(const std::string &userName, const std::string &password) {
    FUNCTION_TRACK
	LOCK_GUARD_WRITE
    try {
			std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("INSERT INTO Users(name, password, create_date, last_acces_date, base_rights) VALUES( ? , ?, CURRENT_TIMESTAMP, '0000-00-00 00:00:00', 0); "));

			pstmt->setString(1, userName);
			pstmt->setString(2, crypt(password));
			pstmt->execute();
			int32_t id = LastInsertId();
			lock.Commit();
			return id;
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }
    return 0;
}

//TODO: sprawdzanie czy użytkownik posiada jakieś pliki

int32_t DataBase::UserRemove(int32_t id) {
    FUNCTION_TRACK
	LOCK_GUARD_WRITE
    try {
			std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("DELETE FROM Users WHERE id = ?"));
			pstmt->setInt(1, id);
			int32_t ret = pstmt->executeUpdate();
			lock.Commit();
			return ret;
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return 0;
}


int32_t DataBase::UserChangePassword(int32_t id, const std::string &newPassword) {
    FUNCTION_TRACK
	LOCK_GUARD_WRITE
    try {
			std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("UPDATE Users SET password = ? where id = ? "));

			pstmt->setString(1, crypt(newPassword));
			pstmt->setInt(2, id);

			int32_t ret = pstmt->executeUpdate();
			lock.Commit();
			return ret;
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return 0;
}

int32_t DataBase::UserChangePassword(std::string &name, const std::string &newPassword) {
    FUNCTION_TRACK
	LOCK_GUARD_WRITE
    try {
			std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("UPDATE Users SET password = ? where `name` = ? "));

			pstmt->setString(1, crypt(newPassword));
			pstmt->setString(2, name);

			int32_t ret = pstmt->executeUpdate();
			lock.Commit();
			return ret;
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return 0;
}

int32_t DataBase::UserUpdateLastAccessDate(int32_t id) {
    FUNCTION_TRACK
	LOCK_GUARD_WRITE
    try {
			std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("UPDATE Users SET last_acces_date = CURRENT_TIMESTAMP where id = ? "));
			pstmt->setInt(1, id);

			int32_t ret = pstmt->executeUpdate();
			lock.Commit();
			return ret;
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }
    return 0;
}

int32_t DataBase::UserAuth(const std::string &userName, const std::string &password) {
    FUNCTION_TRACK
	LOCK_GUARD_READ
    try {
    	std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("SELECT id FROM Users WHERE name = ? and password = ?"));
        pstmt->setString(1, userName);
        pstmt->setString(2, crypt(password));

        std::auto_ptr<sql::ResultSet> res(pstmt->executeQuery());
        if (res->next()) {
            return res->getInt(1);
        }

    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return 0;
}

User DataBase::UserGet(const std::string &userName) {
    FUNCTION_TRACK
	LOCK_GUARD_READ
    User user;
    try {
    	std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("SELECT id, name, Unix_Timestamp(create_date), Unix_Timestamp(last_acces_date), base_rights FROM Users where name = ?"));
        pstmt->setString(1, userName);

        std::auto_ptr<sql::ResultSet> res(pstmt->executeQuery());
        if (res->next()) {
            user.id = res->getInt(1);
            user.name = res->getString(2);
            user.createDate = res->getInt64(3);
            user.lastAccessDate = res->getInt64(4);
            user.rights = res->getInt(5);
        }
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return user;
}

User DataBase::UserGet(int32_t userId) {
    FUNCTION_TRACK
	LOCK_GUARD_READ
    User user;
    try {
    	std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("SELECT id, name, Unix_Timestamp(create_date), Unix_Timestamp(last_acces_date), base_rights FROM Users where id = ?"));

        pstmt->setInt(1, userId);
        std::auto_ptr<sql::ResultSet> res(pstmt->executeQuery());

        if (res->next()) {
            user.id = res->getInt(1);
            user.name = res->getString(2);
            user.createDate = res->getInt64(3);
            user.lastAccessDate = res->getInt64(4);
            user.rights = res->getInt(5);
        }
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return user;
}

int32_t DataBase::UserGetId(const std::string &userName) {
    FUNCTION_TRACK
	LOCK_GUARD_READ

    try {
    	std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("SELECT id FROM Users WHERE name = ?"));
        pstmt->setString(1, userName);

        std::auto_ptr<sql::ResultSet> res(pstmt->executeQuery());
        if (res->next()) {
            return res->getInt(1);
        }
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return 0;
}

int32_t DataBase::UserSetRights(int32_t id, int32_t rights) {
    FUNCTION_TRACK
	LOCK_GUARD_WRITE
    try {
    	std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("UPDATE Users SET base_rights = ? where id = ?"));

        pstmt->setInt(1, rights);
        pstmt->setInt(2, id);

        int32_t ret = pstmt->executeUpdate();
		lock.Commit();
		return ret;
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return 0;
}

int32_t DataBase::UserGetRights(int32_t userId) {
    FUNCTION_TRACK
    User u = UserGet(userId);
    if (0 == u.id)
	{
        throw DataBaseException("Taki użytkownik nie istnieje");
	}
    else
	{
        return u.rights;
	}
}

int32_t DataBase::UserGotGroup(int32_t userId, int32_t groupId) {
    FUNCTION_TRACK
	LOCK_GUARD_READ
    try {
    	std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("select * from UserGroupStorage where id_user = ? and id_group = ? and id_storage is null"));

        pstmt->setInt(1, userId);
        pstmt->setInt(2, groupId);

        std::auto_ptr<sql::ResultSet> res(pstmt->executeQuery());
        return res->next()?1:0;
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return 0;
}

std::vector<Group> DataBase::UserGetGroups(int32_t userId) {
    FUNCTION_TRACK
	LOCK_GUARD_READ
    std::vector<Group> vector;

    try {
    	std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("select g.id, g.name, Unix_Timestamp(g.create_date), g.base_rights from `Group` g, UserGroupStorage ugs where ugs.id_user = ?"));
        pstmt->setInt(1, userId);

        std::auto_ptr<sql::ResultSet> res(pstmt->executeQuery());
        while (res->next()) {
            Group group;
            group.id = res->getInt(1);
            group.name = res->getString(2);
            group.createDate = res->getInt64(3);
            group.baseRights = res->getInt(4);

            vector.push_back(group);
        }

    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return vector;
}

int32_t DataBase::UserJoinGroup(int32_t userId, int32_t groupId) {
    FUNCTION_TRACK
	LOCK_GUARD_WRITE

    try {
    	std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("INSERT INTO UserGroupStorage ( id_user, id_group, id_storage) VALUES( ?, ?, null)"));

        pstmt->setInt(1, userId);
        pstmt->setInt(2, groupId);

        int32_t ret = pstmt->executeUpdate();
	   	lock.Commit();
		return ret;
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return 0;
}

int32_t DataBase::UserLeaveGroup(int32_t userId, int32_t groupId) {
    FUNCTION_TRACK
	LOCK_GUARD_WRITE

    try {
    	std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("DELETE FROM UserGroupStorage where id_user = ? and id_group = ? and id_storage is null"));

        pstmt->setInt(1, userId);
        pstmt->setInt(2, groupId);
        //pstmt->setInt(3, 0);

        int32_t ret = pstmt->executeUpdate();
	   	lock.Commit();
		return ret;
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return 0;
}

std::vector<User> DataBase::UsersList() {
    FUNCTION_TRACK
	LOCK_GUARD_READ

    std::vector<User> vector;

    try {
    	std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("SELECT id, name, Unix_Timestamp(create_date), Unix_Timestamp(last_acces_date), base_rights FROM Users"));

    	std::auto_ptr<sql::ResultSet> res(pstmt->executeQuery());
        while (res->next()) {
            User user;
            user.id = res->getInt(1);
            user.name = res->getString(2);
            user.createDate = res->getInt64(3);
            user.lastAccessDate = res->getInt64(4);
            user.rights = res->getInt(5);

            vector.push_back(user);
        }

    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return vector;
}

int32_t DataBase::UserGotStorage(int32_t userId, int32_t storageId) {
    FUNCTION_TRACK
	LOCK_GUARD_READ
    try {
    	std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("select * from UserGroupStorage where id_user = ? and id_storage = ? and id_group is null"));

        pstmt->setInt(1, userId);
        pstmt->setInt(2, storageId);

		std::auto_ptr<sql::ResultSet> res(pstmt->executeQuery());
		return res->next()?1:0;
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return 0;
}

std::vector<Storage> DataBase::UserGetStorages(int32_t userId) {
    FUNCTION_TRACK
	LOCK_GUARD_READ
    std::vector<Storage> vector;

    try {
    	std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("select id, name,  Unix_Timestamp(create_date), Unix_Timestamp(last_acces_date) FROM Storages s, UserGroupStorage ugs where ugs.id_user = ? and s.id = ugs.id_storage and ugs.id_group is null"));

        pstmt->setInt(1, userId);
        std::auto_ptr<sql::ResultSet> res(pstmt->executeQuery());

        while (res->next()) {
            Storage storage;
            storage.id = res->getInt(1);
            storage.name = res->getString(2);
            storage.createDate = res->getInt64(3);
            storage.lastAccessDate = res->getInt64(4);

            vector.push_back(storage);
        }

    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return vector;
}

int32_t DataBase::UserJoinStorage(int32_t userId, int32_t storageId) {
    FUNCTION_TRACK
	LOCK_GUARD_WRITE

    try {
    	std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("INSERT INTO UserGroupStorage ( id_user, id_group, id_storage) VALUES( ?, null, ?)"));

        pstmt->setInt(1, userId);
        pstmt->setInt(2, storageId);
        //pstmt->setInt(3, 0);

        int32_t ret = pstmt->executeUpdate();
	   	lock.Commit();
		return ret;
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return 0;
}

int32_t DataBase::UserLeaveStorage(int32_t userId, int32_t storageId) {
    FUNCTION_TRACK
	LOCK_GUARD_WRITE

    try {
    	std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("DELETE FROM UserGroupStorage where id_user = ? and id_group is null and id_storage = ?"));

        pstmt->setInt(1, userId);
        pstmt->setInt(2, storageId);

        int32_t ret = pstmt->executeUpdate();
	   	lock.Commit();
		return ret;
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return 0;
}

int32_t DataBase::GroupAdd(const std::string &name) {
    FUNCTION_TRACK
	LOCK_GUARD_WRITE
    try {
			std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("INSERT INTO `Group` (`name`, `create_date`, `base_rights`) VALUES( ? , CURRENT_TIMESTAMP, 0)"));

			pstmt->setString(1, name);
			pstmt->executeUpdate();
			int32_t ret = LastInsertId();
			lock.Commit();
			return ret;
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return 0;
}

int32_t DataBase::GroupRemove(int32_t groupId) {
    FUNCTION_TRACK
	LOCK_GUARD_WRITE
    try {
    	std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("DELETE FROM `Group` where id = ?"));
        pstmt->setInt(1, groupId);

        int32_t ret = pstmt->executeUpdate();
		lock.Commit();
		return ret;
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return 0;
}

Group DataBase::GroupGet(int32_t groupId) {
    FUNCTION_TRACK
	LOCK_GUARD_READ
    Group group;
    try {
    	std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("SELECT id, name, password, Unix_Timestamp(create_date), Unix_Timestamp(last_acces_date), base_rights FROM Group where id = ?"));

        pstmt->setInt(1, groupId);

        std::auto_ptr<sql::ResultSet> res(pstmt->executeQuery());
        if (res->next()) {
            group.id = res->getInt(1);
            group.name = res->getString(2);
            group.createDate = res->getInt64(3);
            group.baseRights = res->getInt(4);
        }
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return group;
}

Group DataBase::GroupGet(const std::string &groupName) {
    FUNCTION_TRACK
	LOCK_GUARD_READ
    Group group;
    try {
    	std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("SELECT id, name, Unix_Timestamp(create_date), base_rights FROM `Group` where name = ?"));
        pstmt->setString(1, groupName);

        std::auto_ptr<sql::ResultSet> res(pstmt->executeQuery());
        if (res->next()) {
            group.id = res->getInt(1);
            group.name = res->getString(2);
            group.createDate = res->getInt64(3);
            group.baseRights = res->getInt(4);
        }
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return group;
}

int32_t DataBase::GroupGetId(const std::string &name) {
    FUNCTION_TRACK
    return this->GroupGet(name).id;
}

int32_t DataBase::GroupSetRights(int32_t id, int32_t rights) {
    FUNCTION_TRACK
	LOCK_GUARD_WRITE
    try {
    	std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("UPDATE Group SET base_rights = ? where id = ?"));

        pstmt->setInt(1, rights);
        pstmt->setInt(2, id);

        int32_t ret = pstmt->executeUpdate();
		lock.Commit();
		return ret;
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return 0;
}

int32_t DataBase::GroupGetRights(int32_t userId) {
    FUNCTION_TRACK
    Group group = GroupGet(userId);
    if (0 == group.id)
        throw DataBaseException("Taka grupa nie istnieje");
    else
        return group.baseRights;
}

std::vector<User> DataBase::GroupGetUsers(int32_t groupId) {
    FUNCTION_TRACK
	LOCK_GUARD_READ
    std::vector<User> vector;

    try {
    	std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("SELECT u.id, u.name, u.Unix_Timestamp(create_date), u.Unix_Timestamp(last_acces_date), u.base_rights FROM Users u, UserGroupStorage ugs where ugs.id_group = ?"));
        pstmt->setInt(1, groupId);
        std::auto_ptr<sql::ResultSet> res(pstmt->executeQuery());
        while (res->next()) {
            User user;
            user.id = res->getInt(1);
            user.name = res->getString(2);
            user.createDate = res->getInt64(3);
            user.lastAccessDate = res->getInt64(4);
            user.rights = res->getInt(5);

            vector.push_back(user);
        }
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return vector;
}

int32_t DataBase::GroupGotStorage(int32_t groupId, int32_t storageId) {
    FUNCTION_TRACK
	LOCK_GUARD_READ

    try {
    	std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("select * from UserGroupStorage where id_storage = ? and id_group = ? LIMIT 1"));

        pstmt->setInt(1, storageId);
        pstmt->setInt(2, groupId);

        std::auto_ptr<sql::ResultSet> res( pstmt->executeQuery() );
        return res->next()?1:0;
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return 0;
}

std::vector<Storage> DataBase::GroupGetStorages(int32_t groupId) {
    FUNCTION_TRACK
	LOCK_GUARD_READ

    std::vector<Storage> vector;

    try {
    	std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("select s.id, u.name, Unix_Timestamp(s.create_date), s.base_rights from Storage s, UserGroupStorage ugs where ugs.id_group = ?"));
    	pstmt->setInt(1, groupId);
    	std::auto_ptr<sql::ResultSet> res(pstmt->executeQuery());
        while (res->next()) {
            Storage storage;
            storage.id = res->getInt(1);
            storage.name = res->getString(2);
            storage.createDate = res->getInt64(3);

            vector.push_back(storage);
        }
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return vector;
}

int32_t DataBase::GroupJoinStorage(int32_t groupId, int32_t storageId) {
    FUNCTION_TRACK
	LOCK_GUARD_WRITE

    try {
    	std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("INSERT INTO UserGroupStorage ( id_user, id_group, id_storage) VALUES( null, ?, ?)"));

        pstmt->setInt(1, groupId);
        pstmt->setInt(2, storageId);

        int32_t ret = pstmt->executeUpdate();
		lock.Commit();
		return ret;
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return 0;
}

int32_t DataBase::GroupLeaveStorage(int32_t groupId, int32_t storageId) {
    FUNCTION_TRACK
	LOCK_GUARD_WRITE

    try {
    	std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("DELETE FROM UserGroupStorage where id_user is null and id_group = ? and id_storage = ?"));

        pstmt->setInt(1, groupId);
        pstmt->setInt(2, storageId);
        //pstmt->setInt(3, 0);

        int32_t ret = pstmt->executeUpdate();
		lock.Commit();
		return ret;
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return 0;
}

std::vector<Group> DataBase::GroupList() {
    FUNCTION_TRACK
	LOCK_GUARD_READ
    std::vector<Group> vector;

    try {
    	std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("SELECT id, name, Unix_Timestamp(create_date), base_rights FROM `Group`"));

    	std::auto_ptr<sql::ResultSet> res(pstmt->executeQuery());
        while (res->next()) {
            Group group;
            group.id = res->getInt(1);
            group.name = res->getString(2);
            group.createDate = res->getInt64(3);
            group.baseRights = res->getInt(4);

            vector.push_back(group);
        }
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return vector;
}

int32_t DataBase::StorageAdd(const std::string &name, const std::string &key) {
    FUNCTION_TRACK
	LOCK_GUARD_WRITE
    try {
			std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("INSERT INTO `Storages` (name, password, create_date, last_acces_date) VALUES( ?, ?, CURRENT_TIMESTAMP, '0000-00-00 00:00:00')"));

			pstmt->setString(1, name);
			pstmt->setString(2, crypt(key));

			pstmt->executeUpdate();

			int32_t ret = LastInsertId();
			lock.Commit();
			return ret;
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return 0;
}

int32_t DataBase::StorageRemove(int32_t id) {
    FUNCTION_TRACK
	LOCK_GUARD_WRITE
    try {
    	std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("DELETE FROM `Storages` where id = ?"));
        pstmt->setInt(1, id);
		int32_t ret = pstmt->executeUpdate();
		lock.Commit();
		return ret;
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return 0;
}

Storage DataBase::StorageGet(int32_t storageId) {
    FUNCTION_TRACK
	LOCK_GUARD_READ
    Storage storage;
    try {
    	std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("SELECT id, name, Unix_Timestamp(create_date), Unix_Timestamp(last_acces_date) FROM Storages where id = ?"));
        pstmt->setInt(1, storageId);

        std::auto_ptr<sql::ResultSet> res(pstmt->executeQuery());
        if (res->next()) {
            storage.id = res->getInt(1);
            storage.name = res->getString(2);

            storage.createDate = res->getInt64(3);
            storage.lastAccessDate = res->getInt64(4);
        }
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return storage;
}

Storage DataBase::StorageGet(const std::string &name) {
    FUNCTION_TRACK
	LOCK_GUARD_READ
    Storage storage;
    try {
    	std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("SELECT id, name, Unix_Timestamp(create_date), Unix_Timestamp(last_acces_date) FROM Storages where name = ?"));

        pstmt->setString(1, name);

        std::auto_ptr<sql::ResultSet> res(pstmt->executeQuery());
        if (res->next()) {
            storage.id = res->getInt(1);
            storage.name = res->getString(2);
            storage.createDate = res->getInt64(3);
            storage.lastAccessDate = res->getInt64(4);
        }
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return storage;
}

int32_t DataBase::StorageGetId(const std::string &name) {
    FUNCTION_TRACK
    return this->StorageGet(name).id;
}

int32_t DataBase::StorageChangeKey(int32_t storageId, const std::string &key) {
    FUNCTION_TRACK
	LOCK_GUARD_WRITE

    try {
    	std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("UPDATE Storages SET password = ? WHERE id = ?"));

        pstmt->setString(1, crypt(key));
        pstmt->setInt(2, storageId);

		int32_t ret = pstmt->executeUpdate();
		lock.Commit();
		return ret;
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return 0;
}

int32_t DataBase::StorageChangeKey(const std::string &storage, const std::string &key) {
    FUNCTION_TRACK
	LOCK_GUARD_WRITE

    try {
    	std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("UPDATE Storages SET password = ? WHERE `name` = ?"));

        pstmt->setString(1, crypt(key));
        pstmt->setString(2, storage);

		int32_t ret = pstmt->executeUpdate();
		lock.Commit();
		return ret;
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return 0;
}

std::vector<Storage> DataBase::StorageList() {
    FUNCTION_TRACK
	LOCK_GUARD_READ
    std::vector<Storage> vector;

    try {
    	std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("SELECT id, name,  Unix_Timestamp(create_date), Unix_Timestamp(last_acces_date) FROM Storages"));

    	std::auto_ptr<sql::ResultSet> res(pstmt->executeQuery());
        while (res->next()) {
            Storage storage;
            storage.id = res->getInt(1);
            storage.name = res->getString(2);
            storage.createDate = res->getInt64(3);
            storage.lastAccessDate = res->getInt64(4);

            vector.push_back(storage);
        }
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }
    return vector;
}

std::vector<User> DataBase::StorageGetUsers(int32_t storageId) {
    FUNCTION_TRACK
	LOCK_GUARD_READ
    std::vector<User> vector;

    try {
    	std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("SELECT u.id, u.name, u.password, u.Unix_Timestamp(create_date), u.Unix_Timestamp(last_acces_date), u.base_rights FROM Users u, UserGroupStorage ugs where ugs.id_storage = ?"));
        pstmt->setInt(1, storageId);
        std::auto_ptr<sql::ResultSet> res(pstmt->executeQuery());
        while (res->next()) {
            User user;
            user.id = res->getInt(1);
            user.name = res->getString(2);
            user.createDate = res->getInt64(3);
            user.lastAccessDate = res->getInt64(4);
            user.rights = res->getInt(6);

            vector.push_back(user);
        }

    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return vector;
}

std::vector<Group> DataBase::StorageGetGroups(int32_t storageId) {
    FUNCTION_TRACK
	LOCK_GUARD_READ
    std::vector<Group> vector;

    try {
    	std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("select g.id, g.name, Unix_Timestamp(g.create_date), g.base_rights from `Group` g, UserGroupStorage ugs where ugs.id_storage = ?"));

        pstmt->setInt(1, storageId);
        std::auto_ptr<sql::ResultSet> res(pstmt->executeQuery());
        while (res->next()) {
            Group group;
            group.id = res->getInt(1);
            group.name = res->getString(2);
            group.createDate = res->getInt64(3);
            group.baseRights = res->getInt(4);

            vector.push_back(group);
        }
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return vector;
}
/*If storage Id = 0, pure virtual folder*/

int32_t DataBase::FolderCreate(const std::string &name, int32_t parentId, int32_t rights, int32_t ownerUserId, int32_t ownerGroupId, int32_t storageId, const std::string &link, bool sync) {
    FUNCTION_TRACK
	LOCK_GUARD_WRITE

    try {
		{
			std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("SELECT id FROM Folders WHERE name = ? AND parent_id = ? LIMIT 1"));
			pstmt->setString(1, name);
			pstmt->setInt(2, parentId);
			std::auto_ptr<sql::ResultSet> res(pstmt->executeQuery());
			if (res->next()) {
				return 0;
			}
		}
		{
			std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("SELECT id FROM `File` WHERE name = ? AND folder_id = ? LIMIT 1"));
			pstmt->setString(1, name);
			pstmt->setInt(2, parentId);
			std::auto_ptr<sql::ResultSet> res(pstmt->executeQuery());
			if (res->next()) {
				return 0;
			}
		}

		uint32_t rightId = 0;
		if (parentId>0)
		{
			std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("SELECT right_nr FROM Folders WHERE id = ? LIMIT 1"));
			pstmt->setInt(1, parentId);
			std::auto_ptr<sql::ResultSet> res(pstmt->executeQuery());
			if (!res->next()) {
				return 0;
			}
			rightId = res->getUInt(1);
		}
		else
		{
			std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("SELECT MAX(right_nr) FROM Folders WHERE parent_id = 0"));
			std::auto_ptr<sql::ResultSet> res(pstmt->executeQuery());
			if (res->next()) {
				rightId = res->getUInt(1)+1;
			}
		}

		if ( rightId > 0 )
		{
			std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("UPDATE Folders SET right_nr = right_nr + 2 WHERE right_nr >= ?"));
			pstmt->setUInt(1, rightId);
			pstmt->executeUpdate();

			pstmt.reset(con->prepareStatement("UPDATE Folders SET left_nr = left_nr + 2 WHERE left_nr > ?"));
			pstmt->setUInt(1, rightId);
			pstmt->executeUpdate();
		}

		std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("INSERT INTO Folders(name, parent_id, left_nr, right_nr, rights, create_date, owner_user, owner_group, link, id_storage, last_modification_date) VALUES( ?, ? , ?, ?, ?, CURRENT_TIMESTAMP, ?, ?, ?, ?, "+std::string(sync?"CURRENT_TIMESTAMP":"'0000-00-00 00:00:00'")+");"));
        pstmt->setString(1, name);
		pstmt->setInt(2, parentId);
        pstmt->setInt(3, rightId);
        pstmt->setInt(4, rightId+1);
        pstmt->setInt(5, rights);
		if (0 != ownerUserId)
			pstmt->setInt(6, ownerUserId);
		else
			pstmt->setNull(6, sql::DataType::INTEGER);
		if (0 != ownerGroupId)
			pstmt->setInt(7, ownerGroupId);
		else
			pstmt->setNull(7, sql::DataType::INTEGER);
        pstmt->setString(8, link);
        pstmt->setInt(9, storageId);

        pstmt->executeUpdate();
		int32_t ret = LastInsertId();
        INFO("CreateFolder - %s, right - %d = %u", name.c_str(), rightId, ret);
		lock.Commit();
		return ret;
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return 0;
}

Folder DataBase::FolderGet(int32_t id) {
    FUNCTION_TRACK
	LOCK_GUARD_READ
    Folder folder;
    try {
    	std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("SELECT id, name, parent_id, rights, create_date, owner_user, owner_group, link, id_storage FROM Folders where id = ?"));
        pstmt->setInt(1, id);


        std::auto_ptr<sql::ResultSet> res(pstmt->executeQuery());
        if (res->next()) {
            folder.id = res->getInt(1);
            folder.name = res->getString(2);
            folder.parentId = res->getInt(3);
            folder.rights = res->getInt(4);

            folder.createDate = res->getInt64(5);
            folder.ownerUserId = res->getInt(6);
            folder.ownerGroupId = res->getInt(7);
            folder.link = res->getString(8);
            folder.storageId = res->getInt(9);
        }
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }
    return folder;
}

int32_t DataBase::FolderExist(int32_t id) {
    FUNCTION_TRACK
    return FolderGet(id).id;
}

Folder DataBase::FolderGet(const std::string &name) {
    FUNCTION_TRACK
	LOCK_GUARD_READ
    Folder folder;
    try {
    	std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("SELECT id, name, parent_id, rights, create_date, owner_user, owner_group, link, id_storage From Folders where name = ?"));

        pstmt->setString(1, name);

        std::auto_ptr<sql::ResultSet> res(pstmt->executeQuery());
        if (res->next()) {
            folder.id = res->getInt(1);
            folder.name = res->getString(2);
            folder.parentId = res->getInt(3);
            folder.rights = res->getInt(4);

            folder.createDate = res->getInt64(5);
            folder.ownerUserId = res->getInt(6);
            folder.ownerGroupId = res->getInt(7);
            folder.link = res->getString(8);
            folder.storageId = res->getInt(9);
        }
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return folder;
}

int32_t DataBase::FolderRemove(int32_t id) {
    FUNCTION_TRACK
	LOCK_GUARD_WRITE
    INFO("FolderRemove - %u", id);
    try {
		//get right & left
		uint32_t r,l;
    	std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("SELECT left_nr, right_nr FROM Folders WHERE id = ?"));
        pstmt->setInt(1, id);
        std::auto_ptr<sql::ResultSet> res(pstmt->executeQuery());
        if (res->next()) {
			r = res->getUInt(2);
			l = res->getUInt(1);
		} else
			return 0;

		pstmt.reset(con->prepareStatement("DELETE a.* FROM `File` as a INNER JOIN Folders as b ON ((a.folder_id = b.id) AND (b.left_nr >= ?) AND (b.right_nr <= ?))"));
		pstmt->setUInt(1, l);
		pstmt->setUInt(2, r);
		int32_t ret = pstmt->executeUpdate();

		pstmt.reset(con->prepareStatement("DELETE FROM Folders WHERE (left_nr >= ?) AND (right_nr <= ?)"));
		pstmt->setUInt(1, l);
		pstmt->setUInt(2, r);
		ret += pstmt->executeUpdate();

		//aktualizacja l i r
		pstmt.reset(con->prepareStatement("UPDATE Folders SET left_nr = left_nr - ?, right_nr = right_nr - ? WHERE (left_nr >= ?)"));
		pstmt->setUInt(1, r-l-1);
		pstmt->setUInt(2, r-l-1);
		pstmt->setUInt(3, l);
		pstmt->executeUpdate();

		lock.Commit();
		return ret;
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return 0;
}

int32_t DataBase::FolderRemove(int32_t id, int32_t storageId, uint64_t timeStamp, bool recursive)
{
	FUNCTION_TRACK
	LOCK_GUARD_WRITE

    try {
        //get link
		uint32_t r,l;
        std::string link;

    	std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("SELECT left_nr, right_nr, link FROM Folders WHERE id = ?"));
        pstmt->setInt(1, id);
        std::auto_ptr<sql::ResultSet> res(pstmt->executeQuery());
        if (res->next()) {
			r = res->getUInt(2);
			l = res->getUInt(1);
            link = res->getString(3);
		} else
			return 0;

        //usun pliki...
        if (!recursive)
        {
            if (0 == timeStamp)
            {
                pstmt.reset(con->prepareStatement("DELETE a.* FROM `File` as a  WHERE (a.folder_id = ?) AND (a.id_storage = ?) AND ((1 = LOCATE(?, a.link)) OR (1 = LOCATE(?, a.link)))"));
            }
            else
            {
                pstmt.reset(con->prepareStatement("DELETE a.* FROM `File` as a WHERE (a.folder_id = ?) AND ((1 = LOCATE(?, a.link)) OR (1 = LOCATE(?, a.link))) AND (a.last_sync_date < FROM_UNIXTIME(?))"));
                pstmt->setUInt64(5, timeStamp);
            }
            pstmt->setUInt(1, id);
            pstmt->setUInt(2, storageId);
            pstmt->setString(3, link+"\\");
            pstmt->setString(4, link+"/");
            pstmt->executeUpdate();
        }
        else
        {
            if (0 == timeStamp)
            {
                pstmt.reset(con->prepareStatement("DELETE a.* FROM `File` as a LEFT JOIN Folders as b ON (b.id = a.folder_id) WHERE (b.left_nr >= ?) AND (b.right_nr <= ?) AND (a.id_storage = ?) AND ((1 = LOCATE(?, a.link)) OR (1 = LOCATE(?, a.link)))"));
            }
            else
            {
                pstmt.reset(con->prepareStatement("DELETE a.* FROM `File` as a LEFT JOIN Folders as b ON (b.id = a.folder_id) WHERE (b.left_nr >= ?) AND (b.right_nr <= ?) AND (a.id_storage = ?) AND ((1 = LOCATE(?, a.link)) OR (1 = LOCATE(?, a.link))) AND (a.last_sync_date < FROM_UNIXTIME(?))"));
                pstmt->setUInt64(6, timeStamp);
            }
            pstmt->setUInt(1, l);
            pstmt->setUInt(2, r);
            pstmt->setUInt(3, storageId);
            pstmt->setString(4, link+"\\");
            pstmt->setString(5, link+"/");
            pstmt->executeUpdate();
        }


        //wybieramy wszystkie puste podfoldery
        if (!recursive)
        {
            if (0 == timeStamp)
            {
                pstmt.reset(con->prepareStatement("SELECT b.id, b.left_nr, b.right_nr FROM Folders as b LEFT JOIN Folders as b2 ON (b2.left_nr>b.left_nr AND b2.right_nr<b.right_nr) LEFT JOIN `File` as f ON (f.folder_id = b.id) WHERE f.id is null AND (b.id = ? OR b.parent_id = ?) AND b2.id is null AND b.id_storage = ? AND ((1 = LOCATE(?, b.link)) OR (1 = LOCATE(?, b.link))) ORDER BY b.right_nr ASC LIMIT 1"));
            }
            else
            {
                pstmt.reset(con->prepareStatement("SELECT b.id, b.left_nr, b.right_nr FROM Folders as b LEFT JOIN Folders as b2 ON (b2.left_nr>b.left_nr AND b2.right_nr<b.right_nr) LEFT JOIN `File` as f ON (f.folder_id = b.id) WHERE f.id is null AND (b.id = ? OR b.parent_id = ?) AND b2.id is null AND b.id_storage = ? AND ((1 = LOCATE(?, b.link)) OR (1 = LOCATE(?, b.link))) AND (b.last_sync_date < FROM_UNIXTIME(?)) ORDER BY b.right_nr ASC LIMIT 1"));
                pstmt->setUInt64(6, timeStamp);
            }
            pstmt->setUInt(1, id);
            pstmt->setUInt(2, id);
            pstmt->setUInt(3, storageId);
            pstmt->setString(4, link+"\\");
            pstmt->setString(5, link+"/");
        }
        else
        {
            if (0 == timeStamp)
            {
                pstmt.reset(con->prepareStatement("SELECT b.id, b.left_nr, b.right_nr FROM Folders as b LEFT JOIN Folders as b2 ON (b2.left_nr>b.left_nr AND b2.right_nr<b.right_nr) LEFT JOIN `File` as f ON (f.folder_id = b.id) WHERE f.id is null AND b.left_nr>=? AND b.right_nr<=? AND b2.id is null AND b.id_storage = ? AND ((1 = LOCATE(?, b.link)) OR (1 = LOCATE(?, b.link))) ORDER BY b.right_nr ASC LIMIT 1"));
            }
            else
            {
                pstmt.reset(con->prepareStatement("SELECT b.id, b.left_nr, b.right_nr FROM Folders as b LEFT JOIN Folders as b2 ON (b2.left_nr>b.left_nr AND b2.right_nr<b.right_nr) LEFT JOIN `File` as f ON (f.folder_id = b.id) WHERE f.id is null AND b.left_nr>=? AND b.right_nr<=? AND b2.id is null AND b.id_storage = ? AND ((1 = LOCATE(?, b.link)) OR (1 = LOCATE(?, b.link))) AND (b.last_sync_date < FROM_UNIXTIME(?)) ORDER BY b.right_nr ASC LIMIT 1"));
                pstmt->setUInt64(6, timeStamp);
            }
            pstmt->setUInt(1, l);
            pstmt->setUInt(2, r);
            pstmt->setUInt(3, storageId);
            pstmt->setString(4, link+"\\");
            pstmt->setString(5, link+"/");
        }

        std::auto_ptr<sql::PreparedStatement> dstmt(con->prepareStatement("DELETE FROM Folders WHERE id = ?"));
        std::auto_ptr<sql::PreparedStatement> d1stmt(con->prepareStatement("UPDATE Folders SET right_nr = right_nr - ? WHERE right_nr > ?"));
        std::auto_ptr<sql::PreparedStatement> d2stmt(con->prepareStatement("UPDATE Folders SET left_nr = left_nr - ? WHERE left_nr > ?"));

        while(true)
        {
            res.reset(pstmt->executeQuery());
            if (!res->next()) break;

            dstmt->setUInt(1, res->getUInt(1));
            d1stmt->setUInt(1, res->getUInt(3)-res->getUInt(2)+1);
            d2stmt->setUInt(1, res->getUInt(3)-res->getUInt(2)+1);
            d1stmt->setUInt(2, res->getUInt(3));
            d2stmt->setUInt(2, res->getUInt(2));

            dstmt->executeUpdate();
            d1stmt->executeUpdate();
            d2stmt->executeUpdate();
        }

    	pstmt.reset(con->prepareStatement("SELECT left_nr, right_nr, link FROM Folders WHERE id = ?"));
        pstmt->setInt(1, id);
        res.reset(pstmt->executeQuery());
        if (res->next()) {
			r = res->getUInt(2);
			l = res->getUInt(1);
		}
        else
        {
            lock.Commit();
            return 1;
        }

        if (!recursive)
        {
            if (0 == timeStamp)
            {
                pstmt.reset(con->prepareStatement("UPDATE Folders SET link = \"\", id_storage = null, last_modification_date = '0000-00-00 00:00:00', last_sync_date = '0000-00-00 00:00:00' WHERE (id = ? OR parent_id = ?) AND id_storage = ? AND ((1 = LOCATE(?, link)) OR (1 = LOCATE(?, link)))"));
            }
            else
            {
                pstmt.reset(con->prepareStatement("UPDATE Folders SET link = \"\", id_storage = null, last_modification_date = '0000-00-00 00:00:00', last_sync_date = '0000-00-00 00:00:00' WHERE (id = ? OR parent_id = ?) AND id_storage = ? AND ((1 = LOCATE(?, link)) OR (1 = LOCATE(?, link))) AND (last_sync_date < FROM_UNIXTIME(?))"));
                pstmt->setUInt64(6, timeStamp);
            }
            pstmt->setUInt(1, id);
            pstmt->setUInt(2, id);
            pstmt->setUInt(3, storageId);
            pstmt->setString(4, link+"\\");
            pstmt->setString(5, link+"/");
        }
        else
        {
            if (0 == timeStamp)
            {
                pstmt.reset(con->prepareStatement("UPDATE Folders SET link = \"\", id_storage = null, last_modification_date = '0000-00-00 00:00:00', last_sync_date = '0000-00-00 00:00:00' WHERE left_nr>=? AND right_nr<=? AND id_storage = ? AND ((1 = LOCATE(?, link)) OR (1 = LOCATE(?, link)))"));
            }
            else
            {
                pstmt.reset(con->prepareStatement("UPDATE Folders SET link = \"\", id_storage = null, last_modification_date = '0000-00-00 00:00:00', last_sync_date = '0000-00-00 00:00:00' WHERE left_nr>=? AND right_nr<=? AND id_storage = ? AND ((1 = LOCATE(?, link)) OR (1 = LOCATE(?, link))) AND (last_sync_date < FROM_UNIXTIME(?))"));
                pstmt->setUInt64(6, timeStamp);
            }
            pstmt->setUInt(1, l);
            pstmt->setUInt(2, r);
            pstmt->setUInt(3, storageId);
            pstmt->setString(4, link+"\\");
            pstmt->setString(5, link+"/");
        }
        pstmt->executeUpdate();

        lock.Commit();
        return 1;
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return 0;
}

int32_t DataBase::FolderRename(int32_t id, const std::string &newName)
{
	FUNCTION_TRACK
	LOCK_GUARD_WRITE

    try {
    	std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("UPDATE Folders SET name = ? WHERE id = ?"));

        pstmt->setString(1, newName);
        pstmt->setInt(2, id);

		int32_t ret = pstmt->executeUpdate();
		lock.Commit();
		return ret;
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return 0;
}

int32_t DataBase::FolderEdit(int32_t id, const std::string &newName, int32_t rights, int32_t ownerUserId, int32_t ownerGroupId, const std::string &link, uint32_t storageId) {
    FUNCTION_TRACK
	LOCK_GUARD_WRITE

    try {
    	std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("UPDATE Folders SET name = ? , rights = ?, owner_user = ? , owner_group = ?, link = ?, id_storage = ?, `last_sync_date` = '0000-00-00 00:00:00' WHERE id = ?"));

        pstmt->setString(1, newName);
        pstmt->setInt(2, rights);
        pstmt->setInt(3, ownerUserId);
        pstmt->setInt(4, ownerGroupId);
		pstmt->setString(5, link);
		if ( storageId !=0 )
			pstmt->setUInt(6, storageId);
			else
			pstmt->setNull(6, sql::DataType::INTEGER);
        pstmt->setInt(7, id);

		int32_t ret = pstmt->executeUpdate();
		lock.Commit();
		return ret;
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return 0;
}

int32_t DataBase::FolderGetId(const std::string &name) {
    FUNCTION_TRACK
    return FolderGet(name).id;
}

int32_t DataBase::FolderMove(int32_t folderId, int32_t newParentFolder) {
    FUNCTION_TRACK
	LOCK_GUARD_WRITE
    try {
        std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("UPDATE Folders SET parent_id = ? where id = ? "));

        pstmt->setInt(1, newParentFolder);
        pstmt->setInt(2, folderId);

		int32_t ret = pstmt->executeUpdate();
		lock.Commit();
		return ret;
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return 0;
}

int32_t DataBase::FolderCopy(int32_t folderId, int32_t newParentFolder) {
    FUNCTION_TRACK
	LOCK_GUARD_WRITE

    try {
		Folder folder = FolderGet(folderId);
		if (0 == folder.id)
			return 0;
        std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("INSERT INTO Folders( name, parent_id, left_nr, right_nr, rights, create_date, owner_user, owner_group, link, id_storage) VALUES( ?, ? , ?, ?, ?, CURRENT_TIMESTAMP, ?, ?, ?, ?); "));

        pstmt->setString(1, folder.name);
        pstmt->setInt(1, newParentFolder);
        pstmt->setInt(2, 0); //TODO: wyliczanie left
        pstmt->setInt(3, 0); //TODO: wyliczanie right
        pstmt->setInt(4, folder.rights);
        pstmt->setInt(5, folder.ownerUserId);
        pstmt->setInt(6, folder.storageId);
        pstmt->setString(7, folder.link);
        pstmt->setInt(8, folder.storageId);

		int32_t ret = pstmt->executeUpdate();
		lock.Commit();
		return ret;
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return 0;
}

std::string DataBase::FolderGetPath(int32_t id) {
    FUNCTION_TRACK
    Folder folder = FolderGet(id);
    std::string path = folder.name;
	//todo tu sie wlasnie uzywa tego L i R i mozna wyciagnac wszystkie parenty naraz jako liste
    while (folder.parentId != 0) {
        folder = FolderGet(folder.parentId);
        path = folder.name = '/' + path;
    }
    return path = '/' + path;
}

std::vector<Folder> DataBase::FolderList(int32_t folderId) {
    FUNCTION_TRACK
	LOCK_GUARD_READ
    std::vector<Folder> vector;

    try {
    	std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("SELECT id, name, parent_id, rights, create_date, owner_user, owner_group, link, id_storage FROM Folders WHERE parent_id = ?"));
		pstmt->setInt(1, folderId);

        std::auto_ptr<sql::ResultSet> res(pstmt->executeQuery());
        while (res->next())
		{
            Folder folder;
            folder.id = res->getInt(1);
            folder.name = res->getString(2);
            folder.parentId = res->getInt(3);
            folder.rights = res->getInt(4);

            folder.createDate = res->getInt64(5);
            folder.ownerUserId = res->getInt(6);
            folder.ownerGroupId = res->getInt(7);
            folder.link = res->getString(8);
            folder.storageId = res->getInt(9);

            vector.push_back(folder);
        }
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return vector;
}

//TODO: foldery i podfoldery, a nie wszystkie foldery

std::vector<Folder> DataBase::FolderListAll() {
    FUNCTION_TRACK
	LOCK_GUARD_READ
    std::vector<Folder> vector;

    try {
    	std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("SELECT id, name, parent_id, rights, create_date, owner_user, owner_group, link, id_storage"));

    	std::auto_ptr<sql::ResultSet> res(pstmt->executeQuery());
        while (res->next()) {

            Folder folder;

            folder.id = res->getInt(1);
            folder.name = res->getString(2);
            folder.parentId = res->getInt(3);
            folder.rights = res->getInt(4);

            folder.createDate = res->getInt64(5);
            folder.ownerUserId = res->getInt(6);
            folder.ownerGroupId = res->getInt(7);
            folder.link = res->getString(8);
            folder.storageId = res->getInt(9);

            vector.push_back(folder);
        }
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return vector;
}

int32_t DataBase::FileCreate(int32_t folderId, const std::string &name, int32_t rights, int32_t ownerUserId, int32_t ownerGroupId, int32_t size, const std::string &link, int32_t idStorage) {
    FUNCTION_TRACK
	LOCK_GUARD_WRITE
    try {
    	std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("INSERT INTO File(folder_id, name, rights, create_date, last_sync_date, last_modification_date, owner_user, owner_group, size, link, id_storage) VALUES( ? , ?, ?, CURRENT_TIMESTAMP, '0000-00-00 00:00:00', '0000-00-00 00:00:00', ?,?, ?, ?, ?)"));

        pstmt->setInt(1, folderId);
        pstmt->setString(2, name);
        pstmt->setInt(3, rights);
        if (0 != ownerUserId)
         pstmt->setInt(4, ownerUserId);
        else
         pstmt->setNull(4, sql::DataType::INTEGER);
        if (0 != ownerGroupId)
         pstmt->setInt(5, ownerGroupId);
        else
         pstmt->setNull(5, sql::DataType::INTEGER);
        pstmt->setInt(6, size);
        pstmt->setString(7, link);
        if (0 != idStorage)
         pstmt->setInt(8, idStorage);
        else
         pstmt->setNull(8, sql::DataType::INTEGER);
		pstmt->executeUpdate();
		int32_t ret = LastInsertId();
		lock.Commit();
        INFO("FileCreate: %d - %d, %s", ret, idStorage, link.c_str());
		return ret;
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return 0;
}

int32_t DataBase::FileEdit(int32_t id, const std::string &newName, int32_t rights, int32_t ownerUserId, int32_t ownerGroupId, const std::string &link, uint32_t storageId)
{
    FUNCTION_TRACK
	LOCK_GUARD_WRITE

    try {
    	std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("UPDATE `Files` SET name = ? , rights = ?, owner_user = ? , owner_group = ?, link = ?, id_storage = ?, `last_sync_date` = '0000-00-00 00:00:00' WHERE id = ?"));

        pstmt->setString(1, newName);
        pstmt->setInt(2, rights);
        pstmt->setInt(3, ownerUserId);
        pstmt->setInt(4, ownerGroupId);
		pstmt->setString(5, link);
		if ( storageId !=0 )
			pstmt->setUInt(6, storageId);
			else
			pstmt->setNull(6, sql::DataType::INTEGER);
        pstmt->setInt(7, id);

		int32_t ret = pstmt->executeUpdate();
		lock.Commit();
		return ret;
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return 0;
}


int32_t DataBase::FileCopy(int32_t fileId, int32_t folderId) {
    FUNCTION_TRACK
	LOCK_GUARD_WRITE
    try {
        File file = FileGet(folderId);

        if (file.id == 0)
            throw DataBaseException("Taki plik nie istnieje");

        std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("INSERT INTO File(folder_id, name, rights, create_date, last_sync_date, last_modification_date, owner_user, owner_group, size, link, id_storage) VALUES( ? , ?, ?, CURRENT_TIMESTAMP, '0000-00-00 00:00:00', '0000-00-00 00:00:00', ?,?, ?, ?, ?)"));

        pstmt->setInt(1, folderId);
        pstmt->setString(2, file.name);
        pstmt->setInt(3, file.rights);
        pstmt->setInt(4, file.ownerUserId);
        pstmt->setInt(5, file.ownerGroupId);
        pstmt->setInt(6, file.size);
        pstmt->setString(7, file.link);
        pstmt->setInt(8, file.storageId);
		int32_t ret = LastInsertId();
		lock.Commit();
		return ret;
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return 0;
}

int32_t DataBase::FileMove(int32_t fileId, int32_t newParentFolder) {
    FUNCTION_TRACK
	LOCK_GUARD_WRITE

    try {
		std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("UPDATE Files SET parent_id = ? where id = ? "));

		pstmt->setInt(1, newParentFolder);
		pstmt->setInt(2, fileId);

		int32_t ret = pstmt->executeUpdate();
		lock.Commit();
		return ret;
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return 0;
}

File DataBase::FileGet(int32_t id) {
    FUNCTION_TRACK
	LOCK_GUARD_READ
    File file;
    try {
    	std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("SELECT id, folder_id, name, rights, create_date, last_sync_date, last_modification_date, owner_user, owner_group, size, link, id_storage FROM File where id = ?"));

        pstmt->setInt(1, id);

        std::auto_ptr<sql::ResultSet> res(pstmt->executeQuery());
        if (res->next()) {

            file.id = res->getInt(1);
            file.parentId = res->getInt(2);
            file.name = res->getString(3);
            file.rights = res->getInt(4);

            file.createDate = res->getInt64(5);
            file.lastAccesDate = res->getInt64(6);
            file.lastModificationDate = res->getInt64(7);

            file.ownerUserId = res->getInt(8);
            file.ownerGroupId = res->getInt(9);
            file.size = res->getInt(10);
            file.link = res->getString(11);
            file.storageId = res->getInt(12);
        }
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return file;
}

uint64_t DataBase::GetTime()
{
    FUNCTION_TRACK
	LOCK_GUARD_READ

    try {
    	std::auto_ptr<sql::Statement> stmt(con->createStatement());
        std::auto_ptr<sql::ResultSet> res(stmt->executeQuery("SELECT CURRENT_TIMESTAMP"));

        if (res->next()) {
            return res->getUInt64(1);
        }
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return 0;
}



File DataBase::FileGet(const std::string &name) {
    FUNCTION_TRACK
	LOCK_GUARD_READ

    File file;

    try {
    	std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("SELECT id, folder_id, name, rights, create_date, last_sync_date, last_modification_date, owner_user, owner_group, size, link, id_storage FROM File where name = ?"));
        pstmt->setString(1, name);
        std::auto_ptr<sql::ResultSet> res(pstmt->executeQuery());

        if (res->next()) {

            file.id = res->getInt(1);
            file.parentId = res->getInt(2);
            file.name = res->getString(3);
            file.rights = res->getInt(4);

            file.createDate = res->getInt64(5);
            file.lastAccesDate = res->getInt64(6);
            file.lastModificationDate = res->getInt64(7);

            file.ownerUserId = res->getInt(8);
            file.ownerGroupId = res->getInt(9);
            file.size = res->getInt(10);
            file.link = res->getString(11);
            file.storageId = res->getInt(12);
        }
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }


    return file;
}

int32_t DataBase::FileGetId(const std::string &name) {
    FUNCTION_TRACK
    return this->FileGet(name).id;
}

int32_t DataBase::FileExist(int32_t fileId) {
    FUNCTION_TRACK
    return this->FileGet(fileId).id;
}

std::vector<File> DataBase::FileList(int32_t folderId) {
    FUNCTION_TRACK
	LOCK_GUARD_READ
    std::vector<File> vector;

    try {
    	std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("SELECT id, folder_id, name, rights, create_date, last_sync_date, last_modification_date, owner_user, owner_group, size, link, id_storage FROM File where folder_id = ?"));

        pstmt->setInt(1, folderId);

        std::auto_ptr<sql::ResultSet> res(pstmt->executeQuery());
        while (res->next()) {
            File file;

            file.id = res->getInt(1);
            file.parentId = res->getInt(2);
            file.name = res->getString(3);
            file.rights = res->getInt(4);

            file.createDate = res->getInt64(5);
            file.lastAccesDate = res->getInt64(6);
            file.lastModificationDate = res->getInt64(7);

            file.ownerUserId = res->getInt(8);
            file.ownerGroupId = res->getInt(9);
            file.size = res->getInt(10);
            file.link = res->getString(11);
            file.storageId = res->getInt(12);

            vector.push_back(file);
        }

    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return vector;
}

int32_t DataBase::FileRemove(int32_t fileId) {
    FUNCTION_TRACK
	LOCK_GUARD_WRITE

    try {
    	std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("DELETE FROM File WHERE id = ?"));
        pstmt->setInt(1, fileId);
		int32_t ret = pstmt->executeUpdate();
		lock.Commit();
		return ret;
    } catch (sql::SQLException &e) {
        LOG_EXCEPTION
    }

    return 0;
}

bool DataBase::_GetInfoUpdate(PathInfo *last)
{
    if ((NULL == last) || (NULL == interface) || (NULL == last->GetParent()) || (!last->GetParent()->IsExists()))
        return false;
    //pobieramy informacje z bazy danych...
    {
        LOCK_GUARD_READ
        do
        {
            std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("SELECT id, rights, owner_user, owner_group, link, id_storage, last_sync_date, last_modification_date, CURRENT_TIMESTAMP FROM `Folders` WHERE parent_id = ? AND name = ? LIMIT 1"));
			pstmt->setUInt(1, last->GetParent()->GetId());
			pstmt->setString(2, last->GetName());
			std::auto_ptr<sql::ResultSet> res(pstmt->executeQuery());
			if (res->next()) {
				last->m_exists = true;
				last->m_type = PATH_FOLDER;
				last->m_id = res->getUInt(1);
				last->m_rights = res->getUInt(2);
				last->m_owner = res->getUInt(3);
				last->m_group = res->getUInt(4);
				last->m_link = res->getString(5);
				last->m_storage_id = res->getUInt(6);
				last->m_syncTime = res->getUInt64(7);
                last->m_modTime = res->getUInt64(8);
                last->m_Time = res->getUInt64(9);
                break;
			}

            pstmt.reset(con->prepareStatement("SELECT id, rights, owner_user, owner_group, link, id_storage, last_sync_date, CURRENT_TIMESTAMP FROM `File` WHERE folder_id = ? AND name = ? LIMIT 1"));
            pstmt->setUInt(1, last->GetParent()->GetId());
			pstmt->setString(2, last->GetName());
			res.reset(pstmt->executeQuery());
			if (res->next()) {
				last->m_exists = true;
				last->m_type = PATH_FILE;
				last->m_id = res->getUInt(1);
				last->m_rights = res->getUInt(2);
				last->m_owner = res->getUInt(3);
				last->m_group = res->getUInt(4);
				last->m_link = res->getString(5);
				last->m_storage_id = res->getUInt(6);
				last->m_syncTime = res->getUInt64(7);
                last->m_Time = res->getUInt64(8);
			}
        } while(false);
    }
    //sprawdzamy czy mamy poprawne informacje... czy nie mineło ponad 60 sekund od czasu ostatniej synchronizacji
    EType result = ETYPE_ERROR;
    if (last->IsExists() && ((0 == last->GetParent()->GetStorageId()) || (last->GetParent()->GetLink().empty()) || (last->IsDirectStorageChild())))
    {
        //jesli element jest aktualny to wychodzimy...
        if ((last->GetTime() - last->GetSyncTime())<SYNC_TIME)
        {
            return true;
        }
        else if ((last->GetStorageId()!=0) && (!last->GetLink().empty()))
        {
            //wymaga odswiezenia, sprawdz element
            result = interface->SyncInfo(last->GetStorageId(), last->GetLink());
        }
        else
            return true;
    }
    else
    {
        //odswiezanie parenta, sprawdzamy czy jest non virtual i sprawdzamy ostatnia date list'y, jesli starsza niz sync, to odswiezamy...
        //sprawdz ostatnie odswiezenie folderu... - 60s
        if (((last->GetParent()->GetTime() - last->GetParent()->GetListTime()) >= SYNC_TIME) && (last->GetParent()->GetStorageId()!=0) && (!last->GetParent()->GetLink().empty()))
        {
            result = interface->SyncInfo(last->GetParent()->GetStorageId(), last->GetParent()->GetLink(), last->GetName());
        }

        if (((ETYPE_NONE == result) || (ETYPE_ERROR == result)) && (last->IsExists()) && (last->GetStorageId()!=0) && (!last->GetLink().empty()))
        {
           //sprawdz element...
           result = interface->SyncInfo(last->GetStorageId(), last->GetLink());
        }
    }

    if (ETYPE_ERROR == result)
        return last->IsExists();

    if (ETYPE_FOLDER == result)
    {
        LOCK_GUARD_READ
        {
            last->m_exists = false;
            std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("SELECT id, rights, owner_user, owner_group, link, id_storage, last_sync_date, last_modification_date, CURRENT_TIMESTAMP FROM `Folders` WHERE parent_id = ? AND name = ? LIMIT 1"));
			pstmt->setUInt(1, last->GetParent()->GetId());
			pstmt->setString(2, last->GetName());
			std::auto_ptr<sql::ResultSet> res(pstmt->executeQuery());
			if (res->next()) {
				last->m_exists = true;
				last->m_type = PATH_FOLDER;
				last->m_id = res->getUInt(1);
				last->m_rights = res->getUInt(2);
				last->m_owner = res->getUInt(3);
				last->m_group = res->getUInt(4);
				last->m_link = res->getString(5);
				last->m_storage_id = res->getUInt(6);
				last->m_syncTime = res->getUInt64(7);
                last->m_modTime = res->getUInt64(8);
                last->m_Time = res->getUInt64(9);
                return true;
			} else result = ETYPE_NONE;
        }
    }

    if (ETYPE_FILE == result)
    {
        LOCK_GUARD_READ
        {
            last->m_exists = false;
            std::auto_ptr<sql::PreparedStatement> pstmt(con->prepareStatement("SELECT id, rights, owner_user, owner_group, link, id_storage, last_sync_date, CURRENT_TIMESTAMP FROM `File` WHERE folder_id = ? AND name = ? LIMIT 1"));
            pstmt->setUInt(1, last->GetParent()->GetId());
			pstmt->setString(2, last->GetName());
			std::auto_ptr<sql::ResultSet> res(pstmt->executeQuery());
			if (res->next()) {
				last->m_exists = true;
				last->m_type = PATH_FILE;
				last->m_id = res->getUInt(1);
				last->m_rights = res->getUInt(2);
				last->m_owner = res->getUInt(3);
				last->m_group = res->getUInt(4);
				last->m_link = res->getString(5);
				last->m_storage_id = res->getUInt(6);
				last->m_syncTime = res->getUInt64(7);
                last->m_modTime = 0;
                last->m_Time = res->getUInt64(8);
                return true;
			} else result = ETYPE_NONE;
        }
    }

    if (ETYPE_NONE == result)
    {
		last->m_exists = false;
		last->m_type = PATH_UNKNOWN;
		last->m_id = 0;
		last->m_rights = 0;
		last->m_owner = 0;
		last->m_group = 0;
		last->m_link.clear();
		last->m_storage_id = 0;
		last->m_syncTime = 0;
        last->m_modTime = 0;
        last->m_Time = 0;
        return false;
    }

    return false;
}

boost::shared_ptr<PathInfo> DataBase::GetInfo(const std::string &path, bool firstRoot)
{
    FUNCTION_TRACK
	std::string tpath = TrimString(path);
	vector<string> tokens;
    boost::split(tokens, tpath, boost::is_any_of("/\\"));

	for(int32_t i = 0; i< tokens.size(); ++i)
	{
		if ((0 == tokens[i].length()) || ("." == tokens[i]))
		{
			tokens.erase(tokens.begin()+i);
			--i;
			continue;
		}
		if (tokens[i] == "..")
		{
			if (0 == i)
				return boost::shared_ptr<PathInfo>();
			tokens.erase(tokens.begin()+i);
			--i;
			tokens.erase(tokens.begin()+i);
			--i;
			continue;
		}

		if (std::string::npos != tokens[i].find_first_of("\\/:*?\"<>|"))
			return boost::shared_ptr<PathInfo>();
		if ((' ' == tokens[i][0]) || (' ' == tokens[i][tokens[i].length()-1]))
			return boost::shared_ptr<PathInfo>();
		if (std::count(tokens[i].begin(), tokens[i].end(), '.') == tokens[i].length())
			return boost::shared_ptr<PathInfo>();
	}

	//build tree..

	PathInfo *last = new PathInfo(NULL, "");
	PathInfo *first = last;
	last->m_path = "/";
	last->m_type = PATH_FOLDER;
	last->m_exists = true;

	if (!tokens.empty())
	{

		try {
            for(uint32_t i = 0; i< ((int32_t)tokens.size()); ++i)
            {
                last = new PathInfo(last, tokens[i]);
                last->m_path = last->GetParent()->GetPath();
                if (!last->IsTerminated()) last->m_path+="/";
                last->m_path+=tokens[i];
                if (tpath[tpath.length()-1] == '\\' || tpath[tpath.length()-1] == '/')
                {
                    last->m_path += "/";
                }
                if (!_GetInfoUpdate(last) && i<tokens.size()-1)
                {
                    return boost::shared_ptr<PathInfo>();
                }
                if ((i<tokens.size()-1) && ((last->GetType()!=PATH_FOLDER) || (!last->IsExists())))
                {
                    return boost::shared_ptr<PathInfo>();
                }
            }
            if (last->IsExists() && last->IsTerminated() && (last->GetType()!=PATH_FOLDER))
            {
                return boost::shared_ptr<PathInfo>();
            }
	    } catch (sql::SQLException &e) {
           LOG_EXCEPTION
		   delete last;
           last = NULL;
		   return boost::shared_ptr<PathInfo>();
        }
	}

	return boost::shared_ptr<PathInfo>(firstRoot?first:last);
}
